using Decav.Reality;
using System;
using System.Collections.Generic;
using System.Text;
using Decav.Security;
using System.Net.Mail;
using Decav.Gatsb.Messaging;
using Decav.Geography;
using Decav.Data;

namespace Decav.Gatsb.Data
{
    /// <summary>
    /// Provides data methods to the Gatsb application.
    /// </summary>
    public interface IGatsbDataAdapter : IDisposable
    {
        bool CheckUserExists(EmailAddress emailAddress);
        bool CheckUserExists(PhoneNumber telNumber);
        User GetUser(EmailAddress emailAddress);
        User GetUser(Guid userId);
        User GetUser(PhoneNumber telNumber);
        UserLoginResult AuthenticateUser(EmailAddress emailAddress, HashedPassword password);
        UserLoginResult AuthenticateUser(PhoneNumber mobileTel, EmailAddress smsEmail);
        UserProfile GetUserProfile(Guid userId);
        void CreateUser(User user, HashedPassword password);
        void CreateUser(User user, HashedPassword password, CreateUserArgs args);
        void UpdateUserProfile(User user, UserProfile profile);
        void CreatePost(Post post);
        void CreateLocation(Location location);
        LocationCheckin[] GetLatestCheckins();
        Post[] GetLatestUserPosts(Guid userId, int postCount);
        Post[] GetLatestLocationPosts(Guid locationId, int postCount);
        Location GetLocation(Guid locationId);
        Location[] FindLocation(LocationSearchCriteria criteria);
        LocationCheckin GetUserCurrentLocation(Guid userId);
        LocationCheckin[] GetUserLocationHistory(Guid userId, int locationCount);
        void AddValidationCode(Guid userId, UserValidationCode code);
        bool ValidateCode(Guid userId, UserValidationCode code);
        void SetUserLocation(Guid userId, Guid locationId);
        User[] FindPeople(PersonSearchCriteria criteria);

        /// <summary>
        /// Gets the locations that a user has created but not filled out all information for.
        /// </summary>
        /// <returns>The locations the users created but not filled out all information for.</returns>
        Location[] GetUserIncompleteLocations();

        /// <summary>
        /// Updates a location that already exists in the database.
        /// </summary>
        /// <param name="location">The location to update.</param>
        void UpdateLocation(Location location);

        /// <summary>
        /// Merges two locations post information together and removes the
        /// location that was merged.
        /// </summary>
        /// <param name="merge">The location that will be merged into the
        /// <paramref name="mergeInto"/> location and then be deleted.</param>
        /// <param name="mergeInto">The location that will be kept as a composite
        /// of the <paramref name="merge"/> location and itself.</param>
        void MergeLocation(Location merge, Location mergeInto);

        /// <summary>
        /// Gets locations that begin with a certain text and are near a specified zip code.
        /// </summary>
        /// <param name="nearZipCode">The zipcode to search near (optional)</param>
        /// <param name="page">The zero-based page to get.</param>
        /// <param name="pageSize">The size of the page.</param>
        /// <returns>The locations matching the specified criteria.</returns>
        PaginationResult<Location> GetLocationsNear(string nearZipCode, int page, int pageSize);

        /// <summary>
        /// Gets locations that begin with a certain text and are near a specified zip code.
        /// </summary>
        /// <param name="userId">The ID of the user to get the locations for.</param>
        /// <param name="page">The zero-based page to get.</param>
        /// <param name="pageSize">The size of the page.</param>
        /// <returns>The locations matching the specified criteria.</returns>
        PaginationResult<Location> GetUserLocations(Guid userId, int page, int pageSize);

        /// <summary>
        /// Gets the latest posts that have been made to Gatsb.
        /// </summary>
        /// <param name="onlyWithAttachments">True when posts returned should
        /// only be ones with images and other attachments.</param>
        /// <param name="onlyFriends">Specifies if only friends posts should be retrieved.</param>
        /// <param name="count">Specifies the number of items to get.</param>
        /// <returns>The top latest posts.</returns>
        Post[] GetLatestPosts(bool onlyWithAttachments, bool onlyFriends, int count);


        void SetupUpdatePhone(Guid userId, PhoneNumber newNumber, TelephoneServiceProvider provider);
        
        /// <summary>
        /// Deletes a <see cref="PostComment"/>.
        /// </summary>
        /// <param name="commentId">The comment to delete.</param>
        void DeleteComment(Guid commentId);

        /// <summary>
        /// Posts a <see cref="PostComment"/> to a post.
        /// </summary>
        /// <param name="comment">The comment to post.</param>
        void PostComment(PostComment comment);

        /// <summary>
        /// Gets the comments that have been placed on a post.
        /// </summary>
        /// <param name="postId">The identifier of the post to get the comments on.</param>
        /// <returns>An array of the comments made on a post.</returns>
        PostComment[] GetPostComments(Guid postId);

        /// <summary>
        /// Gets the attachments for a <see cref="Post"/>.
        /// </summary>
        /// <param name="postId">The ID of the post to get attachments for.</param>
        /// <returns>An array of the attachments on a post.</returns>
        PostAttachment[] GetPostAttachments(Guid postId);

        /// <summary>
        /// Gets messages in the inbox.
        /// </summary>
        /// <param name="status">The status of the messages to get.</param>
        /// <returns>The messages in the inbox.</returns>
        InboxMessage[] GetMessages(MessageStatus status);

        /// <summary>
        /// Gets all friends of the specified user.
        /// </summary>
        /// <param name="userId">The user to get the friends of.</param>
        /// <returns>The array of users that are the friends of this user.</returns>
        User[] GetUserFriends(Guid userId);

        User[] GetLocationCurrentVisitors(Guid locationId);
        User[] GetLocationRecentVisitors(Guid locationId, DateTime sinceDate);

        bool ChangeUserPassword(HashedPassword oldPassword, HashedPassword newPassword);

        /// <summary>
        /// Adds a user as a friend of the currently authenticated user.
        /// </summary>
        /// <param name="UserId">The unique identifier of the user to add as a friend.</param>
        void AddFriend(Guid userId);

        /// <summary>
        /// Rejects a friendship request from a user, or ends a current friendship.
        /// </summary>
        /// <param name="userId">The user to reject the friendship request of</param>
        void EndFriendship(Guid userId);

        /// <summary>
        /// Gets the currently authenticated users status information.
        /// </summary>
        /// <returns>The status information for the current user.</returns>
        UserStatusInfo GetUserStatus();

        /// <summary>
        /// Gets a <see cref="Post"/> that has been made, by its identifier.
        /// </summary>
        /// <param name="id">The unique identifier of the post.</param>
        /// <returns>The post to get.</returns>
        Post GetPost(Guid id);

        /// <summary>
        /// Gets a workflow ID for an SMS session.
        /// </summary>
        /// <param name="recipientAddress">The address of the recipient, as the
        /// session token.</param>
        /// <returns>The unique identifier of the workflow.</returns>
        Guid GetWorkflowForSmsSession(string recipientAddress);

        /// <summary>
        /// Saves a workflow ID and gets an SMS session cookie.
        /// </summary>
        /// <param name="workflowId">The ID of the workflow to save.</param>
        /// <returns>The ID of the session (mailing address) for the session.</returns>
        string SaveWorkflowId(Guid workflowId);

        /// <summary>
        /// Gets or creates a geocoded location using the information passed in to determine
        /// if this geocoded location is currently in the database, or is new and should be
        /// added.  This is used with the search adapters.
        /// </summary>
        /// <param name="name">The name of the location.</param>
        /// <param name="type">The type of the location.</param>
        /// <param name="position">The latitude longitude position.</param>
        /// <param name="city">The city the location is in.</param>
        /// <param name="state">The state the location is in.</param>
        /// <param name="zip">The zip code the location is in.</param>
        /// <param name="street">The optional street address.</param>
        /// <returns>The location that was created or retrieved.</returns>
        Location GetGeocodedLocation(string name, LocationType type,
            LatLongPoint position, string city, string state, string zip, string street);
    }
}
